<?php
namespace App;

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

/**
 * WebSocket服务器实现类
 */
class WebSocketServer implements MessageComponentInterface
{
    /**
     * 当前连接的客户端
     * @var \SplObjectStorage
     */
    protected $clients;
    
    /**
     * 客户端类型映射（厨师端、排队端等）
     * @var array
     */
    protected $clientTypes = [];
    
    /**
     * 会员客户端数据
     * @var array
     */
    protected $memberData = [];
    
    /**
     * 构造函数
     */
    public function __construct()
    {
        $this->clients = new \SplObjectStorage;
        echo "WebSocketServer初始化完成\n";
    }
    
    /**
     * 当有新客户端连接时
     * @param ConnectionInterface $conn
     */
    public function onOpen(ConnectionInterface $conn)
    {
        // 存储新连接
        $this->clients->attach($conn);
        $clientId = $conn->resourceId;
        
        echo "新客户端连接! ID: {$clientId}\n";
    }
    
    /**
     * 当收到客户端消息时
     * @param ConnectionInterface $from
     * @param string $msg
     */
    public function onMessage(ConnectionInterface $from, $msg)
    {
        $clientId = $from->resourceId;
        echo "收到客户端 {$clientId} 的消息: {$msg}\n";
        
        // 尝试解析消息
        try {
            $data = json_decode($msg, true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                echo "消息解析失败: " . json_last_error_msg() . "\n";
                return;
            }
            
            // 处理客户端类型注册消息
            if (isset($data['type']) && $data['type'] === 'register') {
                $this->registerClient($from, $data);
                return;
            }
            
            // 处理其他消息类型
            $this->handleMessage($from, $data);
            
        } catch (\Exception $e) {
            echo "处理消息时出错: " . $e->getMessage() . "\n";
        }
    }
    
    /**
     * 当客户端连接关闭时
     * @param ConnectionInterface $conn
     */
    public function onClose(ConnectionInterface $conn)
    {
        // 移除连接
        $this->clients->detach($conn);
        $clientId = $conn->resourceId;
        
        // 从类型映射中移除
        if (isset($this->clientTypes[$clientId])) {
            unset($this->clientTypes[$clientId]);
        }
        
        echo "客户端 {$clientId} 已断开连接\n";
    }
    
    /**
     * 当发生错误时
     * @param ConnectionInterface $conn
     * @param \Exception $e
     */
    public function onError(ConnectionInterface $conn, \Exception $e)
    {
        echo "客户端 {$conn->resourceId} 发生错误: {$e->getMessage()}\n";
        
        $conn->close();
    }
    
    /**
     * 注册客户端类型
     * @param ConnectionInterface $client
     * @param array $data
     */
    protected function registerClient(ConnectionInterface $client, array $data)
    {
        $clientId = $client->resourceId;
        $clientType = $data['client_type'] ?? 'unknown';
        
        // 设置客户端类型
        $this->clientTypes[$clientId] = $clientType;
        
        // 存储额外信息（如会员的user_id和要监控的order_id）
        if ($clientType === 'member') {
            $this->memberData[$clientId] = [
                'user_id' => $data['user_id'] ?? null,
                'order_id' => $data['order_id'] ?? null
            ];
            
            echo "会员客户端 {$clientId} 已注册，用户ID: {$data['user_id']}, 订单ID: {$data['order_id']}\n";
        }
        
        echo "客户端 {$clientId} 已注册为 {$clientType}\n";
        
        // 发送确认消息
        $response = [
            'type' => 'register_success',
            'message' => '注册成功',
            'client_id' => $clientId,
            'client_type' => $clientType
        ];
        
        try {
            $message = json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            
            // 检查JSON编码是否成功
            if ($message === false) {
                echo "JSON编码失败: " . json_last_error_msg() . "\n";
                return;
            }
            
            $client->send($message);
            echo "已发送注册确认消息给客户端 {$clientId}\n";
        } catch (\Exception $e) {
            echo "向客户端 {$clientId} 发送注册确认消息失败: " . $e->getMessage() . "\n";
        }
    }
    
    /**
     * 处理消息
     * @param ConnectionInterface $from
     * @param array $data
     */
    protected function handleMessage(ConnectionInterface $from, array $data)
    {
        $messageType = $data['type'] ?? 'unknown';
        $clientId = $from->resourceId;
        $clientType = $this->clientTypes[$clientId] ?? 'unknown';
        
        echo "处理 {$clientType} 客户端的 {$messageType} 消息\n";
        
        // 根据消息类型处理
        switch ($messageType) {
            case 'order_new':
                // 新订单通知
                $this->broadcastToType('chef', $data);
                $this->broadcastToType('queue', $data);
                break;
                
            case 'order_status':
                // 订单状态更新
                $this->broadcastToAll($data);
                break;
                
            case 'ping':
                // 心跳检测
                try {
                    $pongResponse = ['type' => 'pong', 'timestamp' => time()];
                    $pongMessage = json_encode($pongResponse, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                    
                    // 检查JSON编码是否成功
                    if ($pongMessage === false) {
                        echo "心跳响应JSON编码失败: " . json_last_error_msg() . "\n";
                        return;
                    }
                    
                    $from->send($pongMessage);
                    // 不记录心跳日志以减少日志量
                } catch (\Exception $e) {
                    echo "发送心跳响应失败: " . $e->getMessage() . "\n";
                }
                break;
                
            default:
                echo "未知消息类型: {$messageType}\n";
                break;
        }
    }
    
    /**
     * 向特定类型的客户端广播消息
     * @param string $type
     * @param array $data
     */
    protected function broadcastToType(string $type, array $data)
    {
        try {
            // 确保数据是有效的数组且有type字段
            if (!is_array($data) || !isset($data['type'])) {
                echo "警告: 尝试广播无效数据\n";
                return;
            }
            
            $message = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            
            // 检查JSON编码是否成功
            if ($message === false) {
                echo "JSON编码失败: " . json_last_error_msg() . "\n";
                return;
            }
            
            $count = 0;
            
            foreach ($this->clients as $client) {
                $clientId = $client->resourceId;
                $clientType = $this->clientTypes[$clientId] ?? 'unknown';
                
                if ($clientType === $type) {
                    try {
                        $client->send($message);
                        $count++;
                    } catch (\Exception $e) {
                        echo "向客户端 {$clientId} 发送消息失败: " . $e->getMessage() . "\n";
                    }
                }
            }
            
            echo "消息已广播给 {$count} 个 {$type} 类型客户端\n";
        } catch (\Exception $e) {
            echo "广播消息时出错: " . $e->getMessage() . "\n";
        }
    }
    
    /**
     * 向所有客户端广播消息
     * @param array $data
     */
    protected function broadcastToAll(array $data)
    {
        try {
            // 确保数据是有效的数组且有type字段
            if (!is_array($data) || !isset($data['type'])) {
                echo "警告: 尝试广播无效数据\n";
                return;
            }
            
            $message = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            
            // 检查JSON编码是否成功
            if ($message === false) {
                echo "JSON编码失败: " . json_last_error_msg() . "\n";
                return;
            }
            
            $count = 0;
            
            foreach ($this->clients as $client) {
                try {
                    $client->send($message);
                    $count++;
                } catch (\Exception $e) {
                    echo "向客户端 {$client->resourceId} 发送消息失败: " . $e->getMessage() . "\n";
                }
            }
            
            echo "消息已广播给所有 {$count} 个客户端\n";
        } catch (\Exception $e) {
            echo "广播消息时出错: " . $e->getMessage() . "\n";
        }
    }
} 